/**
 * \file DSAddIn.cpp
 *
 * \brief Implementation file for class CDSAddIn
 *
 * $Id: DSAddIn.cpp,v 1.1.1.1 2008/04/23 13:29:14 mgh Exp $
 *
 *
 * Copyright (C) 2006 Michael G. Herstine <sp1ff@pobox.com>
 *
 * Permission to use, copy, or modify this source code is hereby granted
 * free of  charge, provided  that this copyright  notice appear  on all
 * copies  and  on   all  source  code  derived  from   this  code.   No
 * representation is made regarding the suitability of this software for
 * any  purpose.  It  is provided  "as  is" without  express or  implied
 * warranty.
 *
 *
 */
#include "stdafx.h"             // Pre-compiled header
#include "AddIn.h"              // For CreateInstanceWithParamItf
#include "DSAddIn.h"            // For class CDSAddIn

#include <TLHELP32.H>

////////////////////////////////////////////////////////////////////////
// Class CDSCommands

void CDSCommands::SetParam(CAddIn *pParent)
{
  ATLASSERT(NULL != pParent);
  m_pParent = pParent;
}

void CDSCommands::SetApplicationObject(IApplication* pApplication)
{
	m_pApplication = pApplication;
}

void CDSCommands::SetViaGui(HANDLE hViaGui)
{
	m_hViaGui = hViaGui;
}

void CDSCommands::Configure()
{
  ATLASSERT(NULL != m_pParent);
  m_pParent->Configure();
}

void CDSCommands::SayHello()
{
  ATLASSERT(NULL != m_pParent);
  m_pApplication->EnableModeless(VARIANT_FALSE);
#if 0
  IDebugger*	pDebugger;
  IGenericProject* pProj; 

  m_pApplication->get_Debugger((IDispatch**)&pDebugger);
  m_pApplication->get_ActiveProject((IDispatch**)&pProj);
  pDebugger->put_JustInTimeDebugging(true);

  WCHAR* p;
  WCHAR* e = L"p";
  TCHAR name[1024];
  TCHAR str[1024];
  int *pp;

  pProj->get_Name(&p);
  wcstombs(name, p, 1024);
  sprintf(name, "%s.exe", name);

  HANDLE h;
  int a = -1;
  HANDLE proc_pool = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, -1);
  PROCESSENTRY32 proc;
  bool find = false;
  if (::Process32First(proc_pool, &proc)) {
	  if (strcmp(name, proc.szExeFile) == 0) {
		  find = true;
	  }
	  else {
		  while (::Process32Next(proc_pool, &proc)) {
			  if (strcmp(name, proc.szExeFile) == 0) {
				  find = true;
				  break;
			  }
		  }
	  }
  }

  if (!find)
	  goto EXIT;

  h = ::OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION, 3, proc.th32ProcessID);

  pDebugger->Evaluate(L"&a", &p);
  wcstombs(str, p, 31);
  pp = (int*) strtoul(str, NULL, 16);
  ::ReadProcessMemory(h, pp, &a, 4, NULL);
  sprintf(str, "a = %d", a);
  ::MessageBox(NULL, str, "ImageDebugAssist", MB_OK | MB_ICONINFORMATION);

  pDebugger->Evaluate(L"p", &p);
  wcstombs(str, p, 31);
  pp = (int*) strtoul(str, NULL, 16);
  ::ReadProcessMemory(h, pp, &a, 4, NULL);
  sprintf(str, "*p = %d", a);
  ::MessageBox(NULL, str, "ImageDebugAssist", MB_OK | MB_ICONINFORMATION);

  pp++;
  a = 3;
  if (FALSE == ::WriteProcessMemory(h, pp, &a, 4, NULL)) {
	  DWORD c = GetLastError();
	  sprintf(str, "error: %u", c);
	  ::MessageBox(NULL, str, "ImageDebugAssist", MB_OK | MB_ICONINFORMATION);
  }

  pDebugger->Evaluate(L"a=1", &p);

  CloseHandle(h);
#else
    viaDialog(m_hViaGui);
#endif

  //---------------
  //m_pParent->SayHello();

  m_pApplication->EnableModeless(VARIANT_TRUE);

EXIT:
  return;
}

////////////////////////////////////////////////////////////////////////
// Class CDSAppEvents

void CDSAppEvents::SetParam(CAddIn *pParent)
{
  ATLASSERT(NULL != pParent);
  m_pParent = pParent;
}

void CDSAppEvents::Connect(IUnknown* pUnk)
{
  HRESULT hr = AtlAdvise(pUnk, this, IID_IApplicationEvents,
                         &m_dwAdvise);
  if (FAILED(hr)) throw _com_error(hr);
}

void CDSAppEvents::Disconnect(IUnknown* pUnk)
{
  AtlUnadvise(pUnk, IID_IApplicationEvents, m_dwAdvise);
}

////////////////////////////////////////////////////////////////////////
// Interface IApplicationEvents

STDMETHODIMP CDSAppEvents::BeforeBuildStart()
{
  ATLTRACE2(atlTraceSampleCAI, 2, "BeforeBuildStart\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::BuildFinish(long /*nErrors*/, long /*nWarnings*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "BuildFinish\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::BeforeApplicationShutDown()
{
  ATLTRACE2(atlTraceSampleCAI, 2, "BeforeApplicationShutDown\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::DocumentOpen(IDispatch * /*pDocument*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "DocumentOpen\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::BeforeDocumentClose(IDispatch * /*pDocument*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "BeforeDocumentClose\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::DocumentSave(IDispatch * /*pDocument*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "DocumentSave\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::NewDocument(IDispatch * /*pDocument*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "NewDocument\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::WindowActivate(IDispatch * /*pWindow*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "WindowActivate\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::WindowDeactivate(IDispatch * /*pWindow*/)
{
  ATLTRACE2(atlTraceSampleCAI, 2, "WindowDeactivate\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::WorkspaceOpen()
{
  ATLTRACE2(atlTraceSampleCAI, 2, "WorkspaceOpen\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::WorkspaceClose()
{
  ATLTRACE2(atlTraceSampleCAI, 2, "WorkspaceClose\n");
  return S_OK;
}

STDMETHODIMP CDSAppEvents::NewWorkspace()
{
  ATLTRACE2(atlTraceSampleCAI, 2, "NewWorkspace\n");
  return S_OK;
}


////////////////////////////////////////////////////////////////////////
// Class CDSAddIn

const TCHAR * const CDSAddIn::VAL_CREATED_DSTB =
_T("CreatedDSTb");

const TCHAR * const CDSAddIn::WND_BASE_NAME =
_T("###SAMPLECAI-MessageWnd-f61141fa-8c74-11da-bf67-0007e946f29c-");

const TCHAR * const CDSAddIn::WND_CLASS_NAME =
_T("###SAMPLECAI-WNDCLASS-f61141f9-8c74-11da-bf67-0007e946f29c###");


CDSAddIn::CDSAddIn() : m_pParent(NULL)
{ 
	m_hViaGui = NULL;
	m_hViaCommands = NULL;
}

/**
 * \brief ATL-defined initialization reoutine
 *
 * \sa OnConnection
 *
 *
 * \return S_OK on success, a failed HRESULT to abort object creation
 *
 *
 * I  don't  care  for  the trivial  constructor/initialization  routine
 * approach.  ATL does, however, and when in Rome...
 *
 * This  method will  create  a  hidden window  for  posting message  to
 * ourselves.   See the documentation  for OnConnection  as to  why this
 * would be useful.  The message window is destroyed in FinalRelease.
 *
 *
 * \pre m_pParent has been initialized
 *
 *
 */

HRESULT CDSAddIn::FinalConstruct()
{
  ATLTRACE2(atlTraceCOM, 2, "CDSAddIn::FinalConstruct\n");

  ATLASSERT(NULL != m_pParent);

  // Create our message window:
  WNDCLASS wndclass;
  ::memset(&wndclass, 0, sizeof(WNDCLASS));
  wndclass.lpfnWndProc   = MsgWindowProc;
  wndclass.hInstance     = _AtlBaseModule.m_hInst;
  wndclass.lpszClassName = WND_CLASS_NAME;

  if (!::RegisterClass(&wndclass))
  {
    DWORD dwStatus = ::GetLastError();
    if (ERROR_CLASS_ALREADY_EXISTS != dwStatus)
    {
      return HRESULT_FROM_WIN32(::GetLastError());
    }
  }

  // We should concoct a unique Window name, in case multiple DevStudio
  // instances are running simulaneously.  We use this DLL's HINSTANCE.
  ATLASSERT(_tcslen(WND_BASE_NAME) + 8 + 3 + 1 <= WND_NAME_STR_LEN);

  TCHAR lpszWndName[WND_NAME_STR_LEN];
  _sntprintf(lpszWndName, WND_NAME_STR_LEN, _T("%s%08x###"),
             WND_BASE_NAME, HandleToUlong(_AtlBaseModule.m_hInst));

  // Create our hidden, message-only Window:
  m_hWnd = ::CreateWindow(WND_CLASS_NAME,         // Window class
                          lpszWndName,            // Window name
                          0U,                     // Window style
                          0,                      // x position
                          0,                      // y position
                          0,                      // width
                          0,                      // height
                          HWND_MESSAGE,           // Parent Window
                          NULL,                   // Menu
                          _AtlBaseModule.m_hInst, // Owning instance
                          this);                  // Create params
  if (NULL == m_hWnd)
  {
    return HRESULT_FROM_WIN32(::GetLastError());
  }

  ATLTRACE2(atlTraceWindowing, 3, "Created a message window with HWND"
            " 0x%08x.\n", m_hWnd);

  return S_OK;
}

void CDSAddIn::FinalRelease()
{
  ATLTRACE2(atlTraceCOM, 2, "CDSAddIn::FinalRelease\n");

  // Destroy *our* message window...
  ::DestroyWindow(m_hWnd);

  // & if that was the last one...
  if (!::FindWindow(WND_CLASS_NAME, NULL))
  {
    // de-register the WNDCLASS.
    ::UnregisterClass(WND_CLASS_NAME, _AtlBaseModule.m_hInst);
  }

} // End CDSAddIn::FinalRelease.

void CDSAddIn::SetParam(CAddIn *pParent)
{
  ATLASSERT(NULL != pParent);

  m_pParent = pParent;
}

////////////////////////////////////////////////////////////////////////
// Interface ISupportsErrorInfo

STDMETHODIMP CDSAddIn::InterfaceSupportsErrorInfo(REFIID riid)
{
  return InlineIsEqualGUID(IID_IDSAddIn, riid) ? S_OK : S_FALSE;
}


////////////////////////////////////////////////////////////////////////
// Interface IDSAddIn

/**
 * \brief Connect to this AddIn
 *
 *
 * \param pApp An IApplication reference on the DevStudio 6.0
 * Application object
 *
 * \param vfFirstTime If this is the first time the AddIn has been
 * loaded, DevStudio will set this to VARIANT_TRUE
 *
 * \param lCookie A cookie this AddIn will use to identifiy itself to
 * DevStudio in assorted method calls
 *
 * \param pvfOnConnection On successful return, this parameter should be
 * set to VARIANT_TRUE.
 *
 * \return S_OK on success, a stock HRESULT otherwise
 *
 *
 * I've implemented  this method  in a different  way from the  code the
 * AppWizard  generates.   First, we  don't  depend  on the  vfFirstTime
 * parameter,  leaving us  the possiblity  of registering  the  AddIn at
 * installation,  so  the user  doesn't  have  to  browse from  Tools  |
 * Customize | Addins & Macro Files.
 *
 * This complicates  toolbar creation,  since a) we  need to  keep track
 * ourselves  whether   or  not  it's  been  created,   and  b)  calling
 * AddCommandBarButton when vfFirstTime is \em not true will fail.
 *
 * I've solved problem a by just writing down a boolean in the Registry.
 * I've  solved problem b  by posting  a message  to our  hidden message
 * window (it turns out that AddCommandBarButton will succeed if we call
 * it outside the context of OnConnection).
 *
 * I learned  how to  do this from  Nick Hodapp's  article "Undocumented
 * Visual C++" ( http://www.codeproject.com/macro/openvc.asp).
 *
 *
 */

STDMETHODIMP CDSAddIn::OnConnection(IApplication *pApp,
                                    VARIANT_BOOL  vfFirstTime,
                                    long          lCookie,
                                    VARIANT_BOOL *pvfOnConnection)
{
  HRESULT hr = S_OK;            // Eventual return value...

  try
  {
    // Validate our parameters...
    if (NULL == pApp)            throw _com_error(E_INVALIDARG);
    if (NULL == pvfOnConnection) throw _com_error(E_POINTER);

	m_hViaCommands = viaCommandsCreate(pApp, VIA_DS);
	m_hViaGui = viaCreate(GetModuleHandle("viagui.dll"), m_hViaCommands);
	

    // & get to work-- assume failure until we know we're done:
    *pvfOnConnection = VARIANT_FALSE;

    ATLTRACE2(atlTraceHosting, 3, "DevStudio is connecting to VisEmacs "
              "%s(pApp is 0x%08x & our cookie is 0x%08x).\n",
              VARIANT_TRUE == vfFirstTime ? "for the first time " :
              " ", pApp, lCookie);

    // Store this for future reference. N.B. The assignment to a smart
    // ptr implicitly calls AddRef.
    m_pApp    = pApp;
    m_lCookie = lCookie;

    // DevStudio wants a dispatch interface describing all the commands
    // we implement.  For now, I've implemented that interface on a
    // separate COM component.  However, given how peculiar that object
    // is, I've chosen *not* to make it externally creatable:
    HRESULT hr;
    IUnknown *pOuterUnk = GetControllingUnknown();
    // N.B. We don't keep a reference to the Commands object around once
    // we've handed it off to DevStudio.
    //-xyt IDispatch *pCommands = NULL;
    //-xyt hr = CreateInstanceWithParamItf(pOuterUnk, m_pParent, &pCommands, &m_pCmds);
	hr = CCommandsObj::CreateInstance(&m_pCmds);
    // 'pCommands' now has one outstanding reference...
    if (FAILED(hr)) throw _com_error(hr);
	m_pCmds->AddRef();
	m_pCmds->SetApplicationObject(pApp);
	m_pCmds->SetViaGui(m_hViaGui);

    // Ok-- we've initialized our data structures & we've got a command
    // object.  It's time to tell DevStudio about *us*.  N.B. DevStudio
    // owill take out another reference:
    LONG lInstance = HandleToLong(_AtlBaseModule.m_hInst);
    hr = m_pApp->SetAddInInfo(lInstance,   // DLL Instance
                              (LPDISPATCH) m_pCmds,   // Dispinterface
                              IDB_DSTBMED, // Medium bmps
                              IDB_DSTBLRG, // Large bmps
                              m_lCookie);  // Our cookie
    //-xyt pCommands->Release();       // No longer need it, since either
                                // DevStudio took out a reference, or we
                                // failed!
    if (FAILED(hr)) throw _com_error(hr);

    // Next, we sink the Application's Events:
    hr = CreateInstanceWithParam(pOuterUnk, m_pParent, &m_pAppEvents);
    if (FAILED(hr)) throw _com_error(hr);

    m_pAppEvents->Connect(m_pApp);

    // The only remaining step is to apprise DevStudio of our commands
    // and their toolbar buttons.  We add commands every time we're
    // loaded, but we only want to create the toolbar once.  The intent
    // was that `vfFirstTime' would be used to distinguish this.
    // However, since we "self-register", we may never be called with
    // this flag set to VARIANT_TRUE.  Hence, we note creation in the
    // Registry.
    bool fCreateTb = false;
    if (VARIANT_TRUE == vfFirstTime)
    {
      // Either we never self-registered, and this really is the first
      // time we've been loaded into DevStudio.
      fCreateTb = true;
    }
    else
    {
      // We should have scribbled down the fact that we created the
      // toolbar, if in fact we've done so.  Look that up:
      CRegKey hKey;
      LONG lStatus = hKey.Create(HKEY_CURRENT_USER, SOFTWARE);
      if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

      lStatus = hKey.Create(hKey, SAMPLES);
      if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

      lStatus = hKey.Create(hKey, SAMPLECAI);
      if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

      DWORD dwCreated;
      lStatus = hKey.QueryDWORDValue(VAL_CREATED_DSTB, dwCreated);
      if (ERROR_FILE_NOT_FOUND == lStatus)
      {
        dwCreated = VAL_CREATED_DSTB_NO;
      }
      else if (ERROR_SUCCESS != lStatus)
      {
        throw _com_error(HRESULT_FROM_WIN32(lStatus));
      }

      fCreateTb = ( dwCreated != VAL_CREATED_DSTB_YES );
    }

    // With that knowledge, we can finally add our commands:
    AddCommands(fCreateTb);

    // Indicate success to DevStudio:
    *pvfOnConnection = VARIANT_TRUE;
  }
  catch (const _com_error &ex)
  {
    LPCTSTR lpszMsg = NULL;

    _bstr_t bstrDsc = ex.Description();
    if (0 != bstrDsc.length()) lpszMsg = bstrDsc;
    else                       lpszMsg = ex.ErrorMessage();

    hr = AtlReportError(CLSID_CoDSAddIn, lpszMsg, IID_IDSAddIn, ex.Error());
  }
  catch (const std::exception &ex)
  {
    hr = AtlReportError(CLSID_CoDSAddIn, ex.what(), IID_IDSAddIn, E_FAIL);
  }

  return hr;

}

/**
 * \brief Disconnect from this AddIn
 *
 *
 * \param vfLastTime  This will  be set to  VARIANT_TRUE if the  user is
 * uninstalling the AddIn; if DevStudio is merely shutting down, it will
 * be set to VARIANT_FALSE
 *
 * \return S_OK on success, a stock HRESULT else
 *
 *
 */

STDMETHODIMP CDSAddIn::OnDisconnection(VARIANT_BOOL /*vfLastTime*/)
{
  HRESULT hr = S_OK;            // Eventual return value...

  try
  {
	  if (m_hViaGui)
		  viaRelease(&m_hViaGui);
	  if (m_hViaCommands)
		  viaCommandsRelease(&m_hViaCommands);

	  m_pCmds->Release();
	  m_pCmds = NULL;
    m_pAppEvents->Disconnect(m_pApp);
    m_pApp = NULL;
  }
  catch (const _com_error &ex)
  {
    LPCTSTR lpszMsg = NULL;

    _bstr_t bstrDsc = ex.Description();
    if (0 != bstrDsc.length()) lpszMsg = bstrDsc;
    else                       lpszMsg = ex.ErrorMessage();

    hr = AtlReportError(CLSID_CoDSAddIn, lpszMsg, IID_IDSAddIn, ex.Error());
  }
  catch (const std::exception &ex)
  {
    hr = AtlReportError(CLSID_CoDSAddIn, ex.what(), IID_IDSAddIn, E_FAIL);
  }

  return hr;
}


////////////////////////////////////////////////////////////////////////
// Toolbar & Command Management

/**
 * \brief Add our commands to DevStudio
 *
 *
 * \param fCreateTb The caller should set this to true in order to
 * create a toolbar in addition to adding our commands
 *
 *
 * Refer to the  documentation for OnConnection for why  we're posting a
 * message to create the toolbar.
 *
 *
 */

void CDSAddIn::AddCommands(bool fCreateTb)
{
  HRESULT hr = S_OK;
  VARIANT_BOOL vfStatus;

  hr = m_pApp->AddCommand(
    CComBSTR(_T("SampleCAI.Configure\n")       // Cmd name
             _T("Configure the Sample AddIn\n")// Button text
             _T("Configure\n")                 // Status bar text
             _T("Configure")),                 // Tooltip
    CComBSTR(_T("Configure")),                 // Disp method name
    0L,                                        // Bitmap offset
    m_lCookie,                                 // DS-provided cookie
    &vfStatus);                                // [out] status

  if (FAILED(hr)) throw _com_error(hr);

  if (VARIANT_FALSE == vfStatus)
  {
    ATLTRACE2(atlTraceHosting, 1, "Warning: DevStudio returned VARIANT"
              "_FALSE when adding the Configure command.\n");
  }

  hr = m_pApp->AddCommand(
    CComBSTR(_T("SampleCAI.SayHello\n") // Cmd name
             _T("Display some text\n")  // Button text
             _T("Say Hello\n")          // Status bar text
             _T("Say Hello")),          // Tooltip
    CComBSTR(_T("SayHello")),           // Disp method name
    1L,                                 // Bitmap offset
    m_lCookie,                          // DS-provided cookie
    &vfStatus);                         // [out] status

  if (FAILED(hr)) throw _com_error(hr);

  if (VARIANT_FALSE == vfStatus)
  {
    ATLTRACE2(atlTraceHosting, 1, "Warning: DevStudio returned VARIANT"
              "_FALSE when adding the SayHello command.\n");
  }

  // If we try to create our toolbar when DevStudio set `vfFirstTime' to
  // VARIANT_FALSE in OnConnect, our attempt will fail.  However, if we
  // return from OnConnect, and *then* make the attempt, the call will
  // succeed.

  // We arrange for this to happen by posting a message to our hidden
  // window & calling ourselves back later.
  if (fCreateTb)
  {
    ATLASSERT(::IsWindow(m_hWnd));
    ::PostMessage(m_hWnd, WM_CREATETOOLBAR, 0U, 0L);
  }
}

/**
 * \brief Create the VisEmacs toolbar in DevStudio
 *
 *
 * One of the annoying things  about writing DevStudio AddIns is that we
 * have no chance  to name it-- the new toolbar  will be called "Toolbar
 * n".  From  Nick Hodapp  "Undocumented Visual C++",  I learned  a cool
 * little trick-- hook  the creation of the toolbar  window & change the
 * window name.
 *
 *
 */

void CDSAddIn::CreateToolbar()
{
  HHOOK hHook = ::SetWindowsHookEx(WH_CBT,
                                   DsToolbarHook,
                                   _AtlBaseModule.m_hInst,
                                   ::GetCurrentThreadId());

  m_pApp->AddCommandBarButton(dsGlyph,
                              CComBSTR(_T("SampleCAI.Configure")),
                              m_lCookie);

  m_pApp->AddCommandBarButton(dsGlyph,
                              CComBSTR(_T("SampleCAI.SayHello")),
                              m_lCookie);

  if (NULL != hHook) ::UnhookWindowsHookEx(hHook);

  CRegKey hKey;
  LONG lStatus = hKey.Create(HKEY_CURRENT_USER, SOFTWARE);
  if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

  lStatus = hKey.Create(hKey, SAMPLES);
  if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

  lStatus = hKey.Create(hKey, SAMPLECAI);
  if (ERROR_SUCCESS != lStatus) throw _com_error(HRESULT_FROM_WIN32(lStatus));

  lStatus = hKey.SetDWORDValue(VAL_CREATED_DSTB, VAL_CREATED_DSTB_YES);
  if (ERROR_SUCCESS != lStatus)
  {
    throw _com_error(HRESULT_FROM_WIN32(lStatus));
  }
}

LRESULT CALLBACK CDSAddIn::DsToolbarHook(int nCode,
                                         WPARAM wParam,
                                         LPARAM lParam)
{
  if (HCBT_CREATEWND == nCode)
  {
    CBT_CREATEWNDA *pcw = (CBT_CREATEWNDA*)lParam;

    if (pcw->lpcs->lpszName)
    {
      if (0 == strncmp(pcw->lpcs->lpszName, "Toolbar", 7))
      {
        strcpy((char*)pcw->lpcs->lpszName, "SmplCAI");
      }
    }
  }

  return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK CDSAddIn::MsgWindowProc(HWND hWnd,
                                         UINT nMsg,
                                         WPARAM wParam,
                                         LPARAM lParam)
{
  LRESULT lResult;

  CDSAddIn *pAddIn = NULL;
  LONG lUserData = ::GetWindowLong(hWnd, GWL_USERDATA);

  if (0L != lUserData)
  {
    pAddIn = reinterpret_cast<CDSAddIn*>(LongToPtr(lUserData));
  }

  try
  {
    switch (nMsg)
    {
    case WM_CREATE:
    {
      LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
      ::SetWindowLong(hWnd, GWL_USERDATA, PtrToLong(pcs->lpCreateParams));
      lResult = ::DefWindowProc(hWnd, nMsg, wParam, lParam);
    }
    break;
    case WM_CREATETOOLBAR:
    {
      pAddIn->CreateToolbar();
      lResult = 0L;
    }
    break;
    default:
      lResult = ::DefWindowProc(hWnd, nMsg, wParam, lParam);
    }
  }
  catch (const _com_error &ex)
  {
    ATLTRACE2(atlTraceWindowing, 0, "WARNING: Unhandled COM exception "
              "in CoDSAddIn's message window procedure: 0x%08x!\n",
              ex.Error());
    ex; // Shutup the compiler in Release builds...
    lResult = -1L;
  }
  catch (const std::exception &ex)
  {
    ATLTRACE2(atlTraceWindowing, 0, "WARNING: Unhandled exception in C"
              "oDSAddIn's message window procedure: %s!\n", ex.what());
    ex; // Shutup the compiler in Release builds...
    lResult = -1L;
  }

  return lResult;
} // End MsgWindowProc.

// Local Variables:
// fill-column: 72
// indent-tabs-mode: nil
// show-trailing-whitespace: t
// End:

// DSAddIn.cpp ends here.
